home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet Info 1994 March
/
Internet Info CD-ROM (Walnut Creek) (March 1994).iso
/
networking
/
ip
/
ka9q
/
alpha.arc
/
AX25SUBR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-07-24
|
11KB
|
460 lines
#include "global.h"
#include "mbuf.h"
#include "timer.h"
#include "ax25.h"
#include "lapb.h"
#include <ctype.h>
struct ax25_cb *ax25_cb[NHASH];
/* Default AX.25 parameters */
int16 t1init = 10000 / MSPTICK; /* FRACK of 10 seconds */
int16 t2init = 1000 / MSPTICK; /* 1 sec acknowledgment delay */
int16 t3init = 0 / MSPTICK; /* No keep-alive polling */
int16 maxframe = 1; /* Stop and wait */
int16 n2 = 10; /* 10 retries */
int16 axwindow = 2048; /* 2K incoming text before RNR'ing */
int16 paclen = 256; /* 256-byte I fields */
int16 pthresh = 128; /* Send polls for packets larger than this */
/* Address hash function. Exclusive-ORs each byte, ignoring
* such insignificant, annoying things as E and H bits
*/
static
int16
ax25hash(s)
struct ax25_addr *s;
{
register char x;
register int i;
register char *cp;
x = 0;
cp = s->call;
for(i=ALEN; i!=0; i--)
x ^= *cp++ & 0xfe;
x ^= s->ssid & SSID;
return uchar(x) % NHASH;
}
/* Look up entry in hash table */
struct ax25_cb *
find_ax25(addr)
register struct ax25_addr *addr;
{
int16 hashval;
register struct ax25_cb *axp;
char i_state;
/* Find appropriate hash chain */
hashval = ax25hash(addr);
/* Search hash chain */
i_state = disable();
for(axp = ax25_cb[hashval]; axp != NULLAX25; axp = axp->next){
if(addreq(&axp->addr.dest,addr)){
restore(i_state);
return axp;
}
}
restore(i_state);
return NULLAX25;
}
/* Remove address entry from hash table */
del_ax25(axp)
register struct ax25_cb *axp;
{
int16 hashval;
char i_state;
if(axp == NULLAX25)
return;
/* Remove from hash header list if first on chain */
hashval = ax25hash(&axp->addr.dest);
i_state = disable();
/* Remove from chain list */
if(ax25_cb[hashval] == axp)
ax25_cb[hashval] = axp->next;
if(axp->prev != NULLAX25)
axp->prev->next = axp->next;
if(axp->next != NULLAX25)
axp->next->prev = axp->prev;
/* Timers should already be stopped, but just in case... */
stop_timer(&axp->t1);
stop_timer(&axp->t2);
stop_timer(&axp->t3);
/* Free allocated resources */
free_q(&axp->txq);
free_q(&axp->rxasm);
free_q(&axp->rxq);
free((char *)axp);
restore(i_state);
}
/* Create an ax25 control block. Allocate a new structure, if necessary,
* and fill it with all the defaults. The caller
* is still responsible for filling in the reply address
*/
struct ax25_cb *
cr_ax25(addr)
struct ax25_addr *addr;
{
void recover(),send_ack(),pollthem(),ax_incom();
register struct ax25_cb *axp;
int16 hashval;
char i_state;
if(addr == NULLAXADDR)
return NULLAX25;
if((axp = find_ax25(addr)) == NULLAX25){
/* Not already in table; create an entry
* and insert it at the head of the chain
*/
/* Find appropriate hash chain */
hashval = ax25hash(addr);
i_state = disable();
axp = (struct ax25_cb *)calloc(1,sizeof(struct ax25_cb));
if(axp == NULLAX25)
return NULLAX25;
/* Insert at beginning of chain */
axp->prev = NULLAX25;
axp->next = ax25_cb[hashval];
if(axp->next != NULLAX25)
axp->next->prev = axp;
ax25_cb[hashval] = axp;
restore(i_state);
}
axp->maxframe = maxframe;
axp->window = axwindow;
axp->paclen = paclen;
axp->proto = V2; /* Default, can be changed by other end */
axp->pthresh = pthresh;
axp->n2 = n2;
axp->t1.start = t1init;
axp->t1.func = recover;
axp->t1.arg = (char *)axp;
axp->t2.start = t2init;
axp->t2.func = send_ack;
axp->t2.arg = (char *)axp;
axp->t3.start = t3init;
axp->t3.func = pollthem;
axp->t3.arg = (char *)axp;
axp->r_upcall = ax_incom;
return axp;
}
/*
* setcall - convert callsign plus substation ID of the form
* "KA9Q-0" to AX.25 (shifted) address format
* Address extension bit is left clear
* Return -1 on error, 0 if OK
*/
int
setcall(out,call)
struct ax25_addr *out;
char *call;
{
int csize;
unsigned ssid;
register int i;
register char *cp,*dp;
char c;
if(out == (struct ax25_addr *)NULL || call == NULLCHAR || *call == '\0'){
return -1;
}
/* Find dash, if any, separating callsign from ssid
* Then compute length of callsign field and make sure
* it isn't excessive
*/
dp = index(call,'-');
if(dp == NULLCHAR)
csize = strlen(call);
else
csize = dp - call;
if(csize > ALEN)
return -1;
/* Now find and convert ssid, if any */
if(dp != NULLCHAR){
dp++; /* skip dash */
ssid = atoi(dp);
if(ssid > 15)
return -1;
} else
ssid = 0;
/* Copy upper-case callsign, left shifted one bit */
cp = out->call;
for(i=0;i<csize;i++){
c = *call++;
if(islower(c))
c = toupper(c);
*cp++ = c << 1;
}
/* Pad with shifted spaces if necessary */
for(;i<ALEN;i++)
*cp++ = ' ' << 1;
/* Insert substation ID field and set reserved bits */
out->ssid = 0x60 | (ssid << 1);
return 0;
}
/* Set a digipeater string in an ARP table entry */
setpath(out,in,cnt)
char *out; /* Target char array containing addresses in net form */
char *in[]; /* Input array of tokenized callsigns in ASCII */
int cnt; /* Number of callsigns in array */
{
struct ax25_addr addr;
char *putaxaddr();
if(cnt == 0)
return;
while(cnt-- != 0){
setcall(&addr,*in++);
addr.ssid &= ~E;
out = putaxaddr(out,&addr);
}
out[-1] |= E;
}
addreq(a,b)
register struct ax25_addr *a,*b;
{
if(memcmp(a->call,b->call,ALEN) != 0)
return 0;
if((a->ssid & SSID) != (b->ssid & SSID))
return 0;
return 1;
}
/* Convert encoded AX.25 address to printable string */
pax25(e,addr)
char *e;
struct ax25_addr *addr;
{
register int i;
char c,*cp;
cp = addr->call;
for(i=ALEN;i != 0;i--){
c = (*cp++ >> 1) & 0x7f;
if(c == ' ')
break;
*e++ = c;
}
if ((addr->ssid & SSID) != 0)
sprintf(e,"-%d",(addr->ssid >> 1) & 0xf); /* ssid */
else
*e = 0;
}
/* Print a string of AX.25 addresses in the form
* "KA9Q-0 [via N4HY-0,N2DSY-2]"
* Designed for use by ARP - arg is a char string
*/
psax25(e,addr)
register char *e;
register char *addr;
{
int i;
struct ax25_addr axaddr;
char tmp[16];
char *getaxaddr();
e[0] = '\0'; /* Give strcat a staritng point */
for(i=0;;i++){
/* Create local copy in host-format structure */
addr = getaxaddr(&axaddr,addr);
/* Create ASCII representation and append to output */
pax25(tmp,&axaddr);
strcat(e,tmp);
if(axaddr.ssid & E)
break;
if(i == 0)
strcat(e," via ");
else
strcat(e,",");
/* Not really necessary, but speeds up subsequent strcats */
e += strlen(e);
}
}
static
char *
getaxaddr(ap,cp)
register struct ax25_addr *ap;
register char *cp;
{
memcpy(ap->call,cp,ALEN);
cp += ALEN;
ap->ssid = *cp++;
return cp;
}
static char *
putaxaddr(cp,ap)
register char *cp;
register struct ax25_addr *ap;
{
memcpy(cp,ap->call,ALEN);
cp += ALEN;
*cp++ = ap->ssid;
return cp;
}
/* Convert a host-format AX.25 header into a mbuf ready for transmission */
struct mbuf *
htonax25(hdr,data)
register struct ax25 *hdr;
struct mbuf *data;
{
struct mbuf *bp;
register char *cp;
register int16 i;
if(hdr == (struct ax25 *)NULL || hdr->ndigis > MAXDIGIS)
return NULLBUF;
/* Allocate space for return buffer */
i = AXALEN * (2 + hdr->ndigis);
if((bp = pushdown(data,i)) == NULLBUF)
return NULLBUF;
/* Now convert */
cp = bp->data;
hdr->dest.ssid &= ~E; /* Dest E-bit is always off */
/* Encode command/response in C bits */
switch(hdr->cmdrsp){
case COMMAND:
hdr->dest.ssid |= C;
hdr->source.ssid &= ~C;
break;
case RESPONSE:
hdr->dest.ssid &= ~C;
hdr->source.ssid |= C;
break;
default:
hdr->dest.ssid &= ~C;
hdr->source.ssid &= ~C;
break;
}
cp = putaxaddr(cp,&hdr->dest);
/* Set E bit on source address if no digis */
if(hdr->ndigis == 0){
hdr->source.ssid |= E;
putaxaddr(cp,&hdr->source);
return bp;
}
hdr->source.ssid &= ~E;
cp = putaxaddr(cp,&hdr->source);
/* All but last digi get copied with E bit off */
for(i=0; i < hdr->ndigis - 1; i++){
hdr->digis[i].ssid &= ~E;
cp = putaxaddr(cp,&hdr->digis[i]);
}
hdr->digis[i].ssid |= E;
cp = putaxaddr(cp,&hdr->digis[i]);
return bp;
}
/* Convert an AX.25 ARP table entry into a host format address structure
* ready for use in transmitting a packet
*/
int
atohax25(hdr,hwaddr,source)
register struct ax25 *hdr;
register char *hwaddr;
struct ax25_addr *source;
{
extern struct ax25_addr mycall;
register struct ax25_addr *axp;
hwaddr = getaxaddr(&hdr->dest,hwaddr); /* Destination address */
ASSIGN(hdr->source,*source); /* Source address */
if(hdr->dest.ssid & E){
/* No digipeaters */
hdr->ndigis = 0;
hdr->dest.ssid &= ~E;
hdr->source.ssid |= E;
return 2;
}
hdr->source.ssid &= ~E;
hdr->dest.ssid &= ~E;
for(axp = hdr->digis; axp < &hdr->digis[MAXDIGIS]; axp++){
hwaddr = getaxaddr(axp,hwaddr);
if(axp->ssid & E){
hdr->ndigis = axp - hdr->digis + 1;
return hdr->ndigis;
}
}
return -1;
}
/* Convert a network-format AX.25 header into a host format structure
* Return -1 if error, number of addresses if OK
*/
int
ntohax25(hdr,bpp)
register struct ax25 *hdr; /* Output structure */
struct mbuf **bpp;
{
register struct ax25_addr *axp;
char *getaxaddr();
char buf[AXALEN];
if(pullup(bpp,buf,AXALEN) < AXALEN)
return -1;
getaxaddr(&hdr->dest,buf);
if(pullup(bpp,buf,AXALEN) < AXALEN)
return -1;
getaxaddr(&hdr->source,buf);
/* Process C bits to get command/response indication */
if((hdr->source.ssid & C) == (hdr->dest.ssid & C))
hdr->cmdrsp = UNKNOWN;
else if(hdr->source.ssid & C)
hdr->cmdrsp = RESPONSE;
else
hdr->cmdrsp = COMMAND;
hdr->ndigis = 0;
if(hdr->source.ssid & E)
return 2; /* No digis */
/* Process digipeaters */
for(axp = hdr->digis;axp < &hdr->digis[MAXDIGIS]; axp++){
if(pullup(bpp,buf,AXALEN) < AXALEN)
return -1;
getaxaddr(axp,buf);
if(axp->ssid & E){ /* Last one */
hdr->ndigis = axp - hdr->digis + 1;
return hdr->ndigis + 2;
}
}
return -1; /* Too many digis */
}
/* Figure out the frame type from the control field
* This is done by masking out any sequence numbers and the
* poll/final bit after determining the general class (I/S/U) of the frame
*/
int16
ftype(control)
register char control;
{
if((control & 1) == 0) /* An I-frame is an I-frame... */
return I;
if(control & 2) /* U-frames use all except P/F bit for type */
return(control & ~PF);
else /* S-frames use low order 4 bits for type */
return(control & 0xf);
}